const gplay = require('google-play-scraper');
const schedule = require('node-schedule');
const config = require("../conf")
const ProxyAgent = require('proxy-agent')


const proxy = new ProxyAgent(config.proxy)


import * as db from '../db';
import * as tool from "../tool/tool"
import { ApiData, DbDataResult } from '../db/class';

import "../tool/date"


const categoryMap = {
    "GAME_ROLE_PLAYING": "角色扮演",
    "GAME_RACING": "竞技游戏",
    "GAME_PUZZLE": "解谜游戏",
    "GAME_ACTION": "动作游戏",
    "GAME_ADVENTURE": "冒险游戏",
    "GAME_BOARD": "棋盘游戏",
    "GAME_CARD": "纸牌游戏",
    "GAME_CASUAL": "休闲游戏",
    "GAME_EDUCATIONAL": "教育游戏",
    "GAME_MUSIC": "音乐游戏",
    "GAME_SIMULATION": "模拟经营",
    "GAME_SPORTS": "体育游戏",
    "GAME_STRATEGY": "策略游戏",
    "GAME_TRIVIA": "益智游戏",
    "GAME_WORD": "文字游戏",
}

const collectionMap = {
    // "TRENDING": "人气蹿升",
    // "TOP_FREE_GAMES": '热门免费',
    // "TOP_PAID_GAMES": '热门付费',
    // "TOP_GROSSING_GAMES": '获利最高',

    "TOP_FREE": '热门免费',
    "TOP_PAID": '热门付费',
    "GROSSING": '获利最高',
}

class GooglePlaySpider {
    constructor() {
        this.Platform = "Android"
        this.ChannelName = "Google Play"
        this.AppIconMap = {}
        this.CollectNum = 200
        this.Cron = '0 0 7 * * *'
    }
}

/* 启动 */
GooglePlaySpider.prototype.run = async function () {
    // 存储目录是否存在，不存在则创建
    tool.fileInit()

    // 测试
    if (config.testMode) {
        this.task()
    } else {
        //定时任务
        this.log("定时任务已开启,cron = " + this.Cron)
        schedule.scheduleJob(this.Cron, () => {
            this.task()
        })
    }
}

/* 任务函数 */
GooglePlaySpider.prototype.task = async function () {
    try {
        await this.getIconMap()
        let nowDate = new Date().format("yyyy-MM-dd")
        this.log(`Google Play Aso 开始采集数据...`);

        this.log("collectRank 开始采集...");
        await this.collectRank(nowDate)
        this.log("collectRank 执行完毕！！！！");

        this.log("collectCategory 开始采集...");
        await this.collectCategory(nowDate)
        this.log("collectCategory 执行完毕！！！！");

        this.log(`Google Play Aso 采集完成，稍后重新采集...`);
    } catch (error) {
        this.log("task error,稍后将重新采集数据,err=" + error);
        tool.sendWarning("task error,err=" + error)
        // 等待两小时后重新请求
        await tool.sleep(1000 * 60 * 60 * 2)
        this.task()
    }
}

/* 打印函数 */
GooglePlaySpider.prototype.log = async function (msg) {
    let nTime = new Date().format("yyyy-MM-dd hh:mm:ss")
    console.log(`${nTime} 【${this.ChannelName}】-【${this.Platform}】：` + msg)
}


/* 获取已存在的icon，避免重复存入 */
GooglePlaySpider.prototype.getIconMap = async function () {
    this.AppIconMap = await db.getIconMap(this.ChannelName, this.Platform)
}

/* 采集函数1 */
GooglePlaySpider.prototype.collectCategory = async function (date) {
    let keys = Object.keys(categoryMap)
    for (let i = 0; i < keys.length; i++) {
        let cate = keys[i]
        let type = categoryMap[cate]
        let tryTimes = 0
        while (tryTimes < 10) {
            try {

                const opts = {
                    category: gplay.category[cate],
                    lang: "zh-CN",
                    fullDetail: true,
                    num: this.CollectNum,
                }

                if (config.testMode) {
                    // 测试模式，开启代理
                    opts.requestOptions = {
                        retry: { limit: 0 },
                        agent: {
                            https: proxy,
                            http: proxy,
                            http2: proxy
                        }
                    }
                }

                
                let res = await gplay.list(opts)
                if (!Array.isArray(res)) return

                var dbDataResult = new DbDataResult()
                dbDataResult.ChannelName = this.ChannelName
                dbDataResult.Date = date
                dbDataResult.Platform = this.Platform
                dbDataResult.RankType = type

                for (let j = 0; j < res.length; j++) {
                    let r = res[j]
                    var apiData = new ApiData()
                    let nDate = "";

                    apiData.AppId = r.appId
                    apiData.GameName = r.title
                    apiData.GameDesc = r.summary
                    apiData.Score = isNaN(Number(r.scoreText)) ? 0 : Number(r.scoreText)
                    apiData.Company = r.developer
                    apiData.DIndex = j

                    if (r.released) {
                        try {
                            nDate = new Date(r.released.replace(/年|月/g, "-").replace(/日/g, "")).format("yyyy-MM-dd")
                        } catch (error) {
                            this.log("replace error,detail.released:" + r.released)
                        }
                    }
                    apiData.OnSaleDate = nDate
                    apiData.CommentCount = r.reviews || 0
                    apiData.TotalDownloadCount = r.maxInstalls || 0
                    apiData.OriginalUrl = r.url || `https://play.google.com/store/apps/details?id=${r.appId}&hl=zh-CN&gl=us`
                    apiData.GameVersion = r.version || ""
                    apiData.TypeName = r.genre || type




                    if (!this.AppIconMap[r.appId]) {
                        //如果数据库没有icon，则存入 
                        apiData.Icon = await tool.getIcon(r.appId, r.icon)
                    }

                    // categoryMap 不采集详情数据 节省流量

                    /* let tryTimes = 0
                    while (tryTimes < 5) {
                        // 详情接口
                        try {
                            apiData = await this.getAppDetail(apiData)
                            break
                        } catch (error) {
                            this.log(`getAppDetail error,type：${type},error：${error},tryTimes：${tryTimes}`)
                            tryTimes++
                        }
                        await tool.sleep(200)
                    }*/

                    dbDataResult.Data.push(apiData)
                    await tool.sleep(200)
                }
                await db.saveData(dbDataResult)
                break
            } catch (error) {
                this.log(`collectCategory ：${type},${error},tryTimes：${tryTimes}`)
                tryTimes++
                await tool.sleep(200)
            }
        }
        if (tryTimes < 10) {
            this.log(`${type}榜采集成功`);
        } else {
            this.log(`${type}采集失败。。。`);
            tool.sendWarning(`${type}采集失败。。。`)
        }
        await tool.sleep(200)
    }
}
/* 采集函数2 */
GooglePlaySpider.prototype.collectRank = async function (date) {
    let keys = Object.keys(collectionMap)
    for (let i = 0; i < keys.length; i++) {
        let cate = keys[i]
        let type = collectionMap[cate]
        let tryTimes = 0
        while (tryTimes < 10) {
            try {
                const opts = {
                    collection: gplay.collection[cate],
                    category:"GAME",
                    lang: "zh-CN",
                    fullDetail: true,
                    num: type == '热门免费' ? 400 : this.CollectNum, // 热门免费400条且拿详情
                }

                if (config.testMode) {
                    // 测试模式，开启代理
                    opts.requestOptions = {
                        retry: { limit: 0 },
                        agent: {
                            https: proxy,
                            http: proxy,
                            http2: proxy
                        }
                    }
                }

                let res = await gplay.list(opts)

                if (!Array.isArray(res)) return

                var dbDataResult = new DbDataResult()
                dbDataResult.ChannelName = this.ChannelName
                dbDataResult.Date = date
                dbDataResult.Platform = this.Platform
                dbDataResult.RankType = type

                for (let j = 0; j < res.length; j++) {
                    let r = res[j]
                    var apiData = new ApiData()
                    let nDate = "";
                    apiData.AppId = r.appId
                    apiData.GameName = r.title
                    apiData.GameDesc = r.summary
                    apiData.Score = isNaN(Number(r.scoreText)) ? 0 : Number(r.scoreText)
                    apiData.Company = r.developer
                    apiData.DIndex = j
                    apiData.BRank = 1

                    if (r.released) {
                        try {
                            nDate = new Date(r.released.replace(/年|月/g, "-").replace(/日/g, "")).format("yyyy-MM-dd")
                        } catch (error) {
                            this.log("replace error,detail.released:" + r.released)
                        }
                    }
                    apiData.OnSaleDate = nDate
                    apiData.CommentCount = r.reviews || 0
                    apiData.TotalDownloadCount = r.maxInstalls || 0
                    apiData.OriginalUrl = r.url || `https://play.google.com/store/apps/details?id=${r.appId}&hl=zh-CN&gl=us`
                    apiData.GameVersion = r.version || ""
                    apiData.TypeName = r.genre || type

                    if (!this.AppIconMap[r.appId]) {
                        //如果数据库没有icon，则存入
                        apiData.Icon = await tool.getIcon(r.appId, r.icon)
                    }

                    // 只有热门免费榜收集app详情
                    /* if (type == '热门免费') {
                        let tryTimes = 0
                        while (tryTimes < 5) {
                            // 详情接口
                            try {
                                apiData = await this.getAppDetail(apiData)
                                break
                            } catch (error) {
                                this.log(`getAppDetail error,type：${type},error：${error},tryTimes：${tryTimes}`)
                                tryTimes++
                            }
                            await tool.sleep(200)
                        }
                    } */

                    dbDataResult.Data.push(apiData)
                    await tool.sleep(200)
                }

                await db.saveData(dbDataResult)
                break
            } catch (error) {
                this.log(`collectRank ：${type},${error},tryTimes：${tryTimes}`)
                tryTimes++
                await tool.sleep(200)
            }
        }

        if (tryTimes < 10) {
            this.log(`${type}榜采集成功`);
        } else {
            this.log(`${type}采集失败。。。`);
            tool.sendWarning(`${type}采集失败。。。`)
        }

        await tool.sleep(200)
    }
}

// 获取应用详情
GooglePlaySpider.prototype.getAppDetail = async function (apiData) {
    try {
        let detail = await gplay.app({
            appId: apiData.AppId,
            lang: "zh-CN",
        })

        if (!detail) return

        let nDate = ""

        if (detail.released) {
            try {
                nDate = new Date(detail.released.replace(/年|月/g, "-").replace(/日/g, "")).format("yyyy-MM-dd")
            } catch (error) {
                this.log("replace error,detail.released:" + detail.released)
            }
        }

        apiData.OnSaleDate = nDate
        apiData.CommentCount = detail.reviews || 0
        apiData.TotalDownloadCount = detail.maxInstalls || 0
        apiData.OriginalUrl = detail.url || apiData.OriginalUrl
        apiData.GameVersion = detail.version || ""
        apiData.TypeName = detail.genre || apiData.TypeName

        return apiData
    } catch (error) {
        throw Error("gplay.app 接口错误")
    }

}


export default GooglePlaySpider